home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Code Resources / NeXT MDEF / NeXT MDEF.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-04  |  13.3 KB  |  393 lines  |  [TEXT/KAHL]

  1.  
  2. // NeXT Menu MDEF Emulator
  3. // Version 1.0
  4. // Jan. 17, 1994 (Right after the Northridge earthquake—whew!!)
  5. // Last Update: May 4, 1994
  6. // by Hiep Dam, 3G Software
  7. // Contact: America Online -> StarLabs
  8. //          Delphi         -> StarLabs
  9. //          Internet       -> starlabs@aol.com, starlabs@delphi.com
  10. //            Snail mail       -> Hiep Dam
  11. //                              2226 Parkside Ave #302
  12. //                              Los Angeles, CA 90031
  13.  
  14. // ----------------------------------------------------------------------
  15.  
  16. // FREE! FREE! FREE!
  17. // This code & MDEF are in the public domain. Use it at your own discretion.
  18. // I am not liable for your own foibles.
  19.  
  20. // ----------------------------------------------------------------------
  21.  
  22. // Notes:
  23. //
  24. //         1) This MDEF does not support meta-characters. It doesn't parse
  25. //           menu item text, and draws the menu items' text AS IS. If you want to
  26. //           add cmd-keys or sub-menus during *run-time*, use _SetItemCmd or the
  27. //           appropriate Menu Manager trap.
  28. //
  29. //        2) Nor does this menu MDEF support text styles or icons.
  30. //           It doesn't support "mctb" resources either (since the MDEF is
  31. //           already in color, this would defeat the MDEF's purpose). All this
  32. //           stuff, though, should be easy to add & implement...
  33. //
  34. //        3) This MDEF *does* support cmd-keys. Yeah!
  35. //
  36. //        4) This MDEF supports item marks, so checkmarks, etc are usable.
  37. //
  38. //        5) This MDEF makes several IMPORTANT *assumptions* about the environment
  39. //           it's running on. Running in an incorrect environment will result
  40. //           in messy crashes.
  41. //            a) Color Quickdraw is present. It uses RGBColors to draw the menu,
  42. //               not the old-style 8-color Quickdraw model. There is no check
  43. //               to see if Color Quickdraw is available or not. If the MDEF is
  44. //               running in a b&w environment, there will be an "unimplemented
  45. //               trap" error. You can add b&w support yourself or add checks to
  46. //               prevent the MDEF from running if Color Quickdraw isn't available.
  47. //            b) System 7 is present. The cmd-key clover symbol is drawn with
  48. //               Chicago (since that's the only font for sure that has this symbol)
  49. //               but the symbol is drawn at 9-point. If TrueType is present, as
  50. //               in the case of System 7, you'll get a funky but readable cmd-key
  51. //               clover. If not present, oh well...
  52. //
  53. //        6) The skeletal portions of this code were derived from an example MDEF
  54. //           included in THINK Reference. See "Custom Menus" in the Menu Manager
  55. //           section.
  56.  
  57.  
  58. // ----------------------------------------------------------------------
  59.  
  60. #include "NeXT MDEF.h"
  61.  
  62. // ----------------------------------------------------------------------
  63.  
  64. typedef enum MDEFconstants {
  65.     // These constants were used with Geneva 9; if you use any other font
  66.     // with this MDEF, you might have to change some values to get your
  67.     // menu to look nice...
  68.     rectPadding  = 1,            // Padding between menu item & whole menu
  69.     heightPad    = 6,            // Vertical padding between text & menu item (x2)
  70.     widthPad     = 6,            // Horizontal padding between text & menu item (x2)
  71.     textHtPad     = 1,            // Vertical offset for "balanced" menu item text
  72.     cmdKeyPad     = 6,            // Horizontal padding added if has cmd key
  73.     subMenuPad     = 12,            // Horizontal padding added if has submenu
  74.     subMenuHt    = 6,            // Height of submenu triangle
  75.     subMenuWd    = 6,            // Width of submenu triangle
  76.     hilite       = true,        // Hilite status of menu item (selected or not)
  77.     unhilite     = false,
  78.  
  79.     menuFont     = geneva,
  80.     menuSize     = 9,
  81.     menuFace     = 0,
  82.     sysTextMode  = srcOr,
  83.     changeFont   = true,
  84.     
  85.     kBlack         = 0,            // Some RGBColor constants
  86.     kWhite         = 65535,
  87.     kLtGray         = 56797,       // light (56797) or darker (48059)
  88.     kDkGray         = 17467        // 17467 (lighter) or darker (8738)
  89. //    kLtGray         = 52428,        // Older color constants
  90. //    kDkGray         = 8738
  91. };
  92.  
  93. // MDEFColors struct.
  94. // Used for keeping track of menu colors, from function to function,
  95. // since we aren't allowed to have globals (though we can if we want
  96. // to, using the A4 register, but that's too skanky for me).
  97.  
  98. typedef struct MDEFcolors {
  99.     struct RGBColor black;
  100.     struct RGBColor white;
  101.     struct RGBColor ltGray;
  102.     struct RGBColor dkGray;
  103. };
  104.  
  105.  
  106. // ----------------------------------------------------------------------
  107.  
  108. // Some prototypes
  109. void FillInColor(RGBColor *theColor, unsigned short r, unsigned short g, unsigned short b);
  110. void InitMDEFColors(MDEFcolors *theColors);
  111. short GetMenuItemHeight();
  112. void GetMenuItemRect(Rect *menuRect, Rect *itemRect, short whichItem);
  113. Boolean IsItemDisabled(MenuHandle whichMenu, short whichItem);
  114. short GetMenuWidth(MenuHandle whichMenu, short numItems);
  115. void DoSizeMsg(MenuHandle whichMenu, Rect *menuRect);
  116. void DoDrawMsg(MenuHandle whichMenu, Rect *menuRect);
  117. void DoChooseMsg(MenuHandle whichMenu, Rect *menuRect, Point hitPt, short *itemID);
  118. void DrawMenuItem(MenuHandle whichMenu, Rect *menuRect, short whichItem,
  119.                     MDEFconstants hiliteState, MDEFcolors *menuColors);
  120.  
  121. // ----------------------------------------------------------------------
  122.  
  123. // Main.
  124. // This is the entrypoint for the MDEF. So what does that mean? Simply
  125. // this is the function that will be called when the MDEF is used.
  126. // It checks what is the current message sent to it, case goes
  127. // thru a switch statement to find the correct handler for the msg.
  128.  
  129. pascal void main(short msg, MenuHandle whichMenu, Rect *menuRect, Point hitPt,
  130.                         short *itemID) {
  131.     // Change the font from system font (Chicago) to something more interesting?
  132.     if (changeFont) {
  133.         TextFont(menuFont);
  134.         TextSize(menuSize);
  135.         TextFace(menuFace);
  136.     }
  137.  
  138.     switch (msg) {
  139.         case mDrawMsg: {
  140.             DoDrawMsg(whichMenu, menuRect);
  141.         } break;
  142.     
  143.         case mChooseMsg: {
  144.             DoChooseMsg(whichMenu, menuRect, hitPt, itemID);
  145.         } break;
  146.     
  147.         case mSizeMsg: {
  148.             DoSizeMsg(whichMenu, menuRect);
  149.         } break;
  150.     
  151.         case mPopUpMsg: {
  152.             short itemCount = CountMItems(whichMenu);
  153.             menuRect->top = hitPt.h - ((*itemID - 1) * GetMenuItemHeight());
  154.             menuRect->left = hitPt.v;
  155.             menuRect->right = menuRect->left + GetMenuWidth(whichMenu, itemCount);
  156.             menuRect->bottom = menuRect->top + (itemCount * GetMenuItemHeight());
  157.         } break;
  158.         
  159.         case mDrawItemMsg: {
  160.             // Unused for the moment since I don't know what this msg is for.
  161.         } break;
  162.         
  163.         case mCalcItemMsg: {
  164.             // Ditto for this dude.
  165.         } break;
  166.     }    // end of switch
  167.  
  168.     // Polite manners: if we changed the font, restore the system font upon
  169.     // exiting...
  170.     if (changeFont) {
  171.         TextFont(systemFont);
  172.         TextSize(12);
  173.         TextFace(0);
  174.     }
  175. } // END main
  176.  
  177. // ----------------------------------------------------------------------
  178.  
  179. // IsItemDisabled.
  180. // Finds out whether the given menu item is disabled or not. Note though
  181. // that we also have to check if the *entire* menu is disabled or not, in
  182. // addition to the menu item. We do this by checking bit 0 of the
  183. // enableFlags field in the menuInfo structure of a menu.
  184.  
  185. Boolean IsItemDisabled(MenuHandle whichMenu, short whichItem) {
  186.     return(!BitTst(&(*whichMenu)->enableFlags, 31 - whichItem) ||
  187.            !BitTst(&(*whichMenu)->enableFlags, 31 - 0));
  188. } // END IsItemDisabled
  189.  
  190. // ----------------------------------------------------------------------
  191.  
  192. // GetMenuItemHeight.
  193. // Get the height of any single menu item. If you wish to add icons
  194. // to your menu, you'll have to change this to accomodate larger icons.
  195. // This simply calls _GetFontInfo.
  196.  
  197. short GetMenuItemHeight() {
  198.     FontInfo theInfo;
  199.     GetFontInfo(&theInfo);
  200.     return(theInfo.ascent + (heightPad * 2));
  201. } // END GetMenuItemHeight
  202.  
  203. // ----------------------------------------------------------------------
  204.  
  205. // GetMenuHeight.
  206. // Gets the height of a single menu item, and finds the height
  207. // of the whole menu by multiplying a single menu item height
  208. // by the number of menu items.
  209.  
  210. short GetMenuHeight(short numItems) {
  211.     return(numItems * GetMenuItemHeight());
  212. } // END GetMenuHeight
  213.  
  214. // ----------------------------------------------------------------------
  215.  
  216. // GetMenuWidth.
  217. // Gets the width of the entire menu, by finding the width of the
  218. // widest menu item in the menu. Polls each menu item for its width,
  219. // keeping track of the largest width.
  220. // Accounts for submenu "triangles" and cmd-keys in menu item width.
  221.  
  222. short GetMenuWidth(MenuHandle whichMenu, short numItems) {
  223.     Str255 itemText;
  224.     short maxLength = 0;
  225.     short curLength = 0;
  226.     short theChar;
  227.     short cmdWidth;
  228.     short checkWidth;
  229.     
  230.     checkWidth = StringWidth("\p√") + 4 + 4;    // 4 = left & right padding
  231.     cmdWidth = StringWidth("\pW");            // "W" is widest character
  232.     cmdWidth += CharWidth(17);                // "Cmd" key character
  233.  
  234.     for (short i = 1; i <= numItems; i++) {
  235.         GetItem(whichMenu, i, itemText);
  236.         curLength = StringWidth(itemText);
  237.  
  238.         GetItemCmd(whichMenu, i, &theChar);
  239.         if (theChar == hMenuCmd)
  240.             curLength += subMenuPad;
  241.         else if (theChar != 0)
  242.             curLength += (cmdWidth + cmdKeyPad);
  243.  
  244.         //GetItemMark(whichMenu, i, &theChar);
  245.         //if (theChar != noMark)
  246.         //    checkWidth = StringWidth("\p√ ");
  247.         curLength += checkWidth;
  248.  
  249.         if (curLength > maxLength)
  250.             maxLength = curLength;
  251.     }
  252.  
  253.     return(maxLength + (widthPad * 2));
  254. } // END GetMenuWidth
  255.  
  256. // ----------------------------------------------------------------------
  257.  
  258. // GetMenuItemRect.
  259. // Obvious.
  260.  
  261. void GetMenuItemRect(Rect *menuRect, Rect *itemRect, short whichItem) {
  262.     short oneHeight = GetMenuItemHeight();
  263.  
  264.     itemRect->left   = menuRect->left;
  265.     itemRect->right  = menuRect->right;
  266.     itemRect->top    = menuRect->top + (oneHeight * (whichItem - 1));
  267.     itemRect->bottom = itemRect->top + oneHeight;
  268. } // END GetMenuItemRect
  269.  
  270. // ----------------------------------------------------------------------
  271.  
  272. // DoSizeMsg.
  273. // Even more obvious (más o menos)
  274.  
  275. void DoSizeMsg(MenuHandle whichMenu, Rect *menuRect) {
  276.     short itemCount = CountMItems(whichMenu);
  277.  
  278.     (*whichMenu)->menuWidth  = GetMenuWidth(whichMenu, itemCount);
  279.     (*whichMenu)->menuHeight = GetMenuHeight(itemCount);
  280. } // END DoSizeMsg
  281.  
  282. // ----------------------------------------------------------------------
  283.  
  284. // DoDrawMsg.
  285. // Erases the entire menu, and calls each menu item individually to
  286. // draw itself.
  287.  
  288. void DoDrawMsg(MenuHandle whichMenu, Rect *menuRect) {
  289.     short itemCount = CountMItems(whichMenu);
  290.  
  291.     MDEFcolors menuColors;
  292.     InitMDEFColors(&menuColors);
  293.  
  294.     RGBBackColor(&menuColors.ltGray);
  295.     EraseRect(menuRect);
  296.  
  297.     for (short i = 1; i <= itemCount; i++) {
  298.         DrawMenuItem(whichMenu, menuRect, i, unhilite, &menuColors);
  299.     }
  300.  
  301.     RGBForeColor(&menuColors.black);
  302.     RGBBackColor(&menuColors.white);
  303. } // END DoDrawMsg
  304.  
  305. // ----------------------------------------------------------------------
  306.  
  307. // DrawMenuItem.
  308. // The "meat" of this MDEF. Does the actual drawing.
  309. // Draws the menu item's 3D frame, item text, cmd-keys, and submenu symbols.
  310. // It does this and also accounts for menu item's enabled/disabled status,
  311. // among other things. Pretty tedious.
  312. // A quick hack but the drawing speed was fine on my IIsi. The drawing
  313. // could be sped up a bit, I suppose, but since I can't see any noticeable
  314. // delay as is, I won't optimize the drawing any. This shouldn't stop you,
  315. // though!!   :)
  316.  
  317. #include "3DPushIn.c++"
  318.  
  319. // ----------------------------------------------------------------------
  320.  
  321. // FindMenuItem.
  322. // Given a point, find if this point is within the rect of any menu
  323. // item. If so, return the item, else 0.
  324.  
  325. short FindMenuItem(MenuHandle whichMenu, Rect *menuRect, Point hitPt) {
  326.     Rect itemRect;
  327.     short itemHit = 0;
  328.     short itemCount = CountMItems(whichMenu);
  329.     
  330.     for (short i = 1; i <= itemCount; i++) {
  331.         GetMenuItemRect(menuRect, &itemRect, i);
  332.         if (PtInRect(hitPt, &itemRect)) {
  333.             itemHit = i;
  334.             break;
  335.         }
  336.     }
  337.     return(itemHit);
  338. } // END FindMenuItem
  339.  
  340. // ----------------------------------------------------------------------
  341.  
  342. // DoChooseMsg.
  343. // This is the only other function which calls DrawMenuItem, other than
  344. // DoDrawMsg. Takes care of the hiliting/unhiliting of menu items.
  345.  
  346. void DoChooseMsg(MenuHandle whichMenu, Rect *menuRect, Point hitPt, short *itemID) {
  347.     Str255 itemText;
  348.     MDEFcolors menuColors;
  349.     InitMDEFColors(&menuColors);
  350.     short mouseItem = FindMenuItem(whichMenu, menuRect, hitPt);
  351.  
  352.     if (mouseItem == 0) {            // out of bounds or disabled
  353.         DrawMenuItem(whichMenu, menuRect, *itemID, unhilite, &menuColors);
  354.         *itemID = 0;                // return "cancel" code
  355.     }
  356.     else if (mouseItem != *itemID) {
  357.         // Ok, user chose new menu item. Check to see if it's a valid menu
  358.         // item (i.e. not disabled or a divider)
  359.         GetItem(whichMenu, mouseItem, itemText);
  360.         if ((itemText[1] == '-') || IsItemDisabled(whichMenu, mouseItem)) {
  361.             DrawMenuItem(whichMenu, menuRect, *itemID, unhilite, &menuColors);
  362.             *itemID = 0;
  363.         }
  364.         else {
  365.             DrawMenuItem(whichMenu, menuRect, *itemID, unhilite, &menuColors);    // unhilight previous
  366.             DrawMenuItem(whichMenu, menuRect, mouseItem, hilite, &menuColors);    // hilight new
  367.             *itemID = mouseItem;         // return new
  368.         }
  369.     }
  370. } // END DoChooseMsg
  371.  
  372. // ----------------------------------------------------------------------
  373.  
  374. // FillInColor.
  375. // If you use RGBColors, no doubt you'll be using some function similar to this.
  376. // Now why didn't Apple include a function like this? Less overhead, I guess.
  377.  
  378. void FillInColor(RGBColor *theColor, unsigned short r, unsigned short g, unsigned short b) {
  379.     theColor->red   = r;
  380.     theColor->green = g;
  381.     theColor->blue  = b;
  382. } // END FillInColor
  383.  
  384. // ----------------------------------------------------------------------
  385.  
  386. void InitMDEFColors(MDEFcolors *theColors) {
  387.     FillInColor(&theColors->white, kWhite, kWhite, kWhite);
  388.     FillInColor(&theColors->black, kBlack, kBlack, kBlack);
  389.     FillInColor(&theColors->ltGray, kLtGray, kLtGray, kLtGray);
  390.     FillInColor(&theColors->dkGray, kDkGray, kDkGray, kDkGray);
  391. } // END InitMDEFColors
  392.  
  393. // END NeXT MDEF.c++